package cr.co.tse.padronelectoral;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.store.SimpleFSDirectory;

import cr.co.tse.padronelectoral.domain.Junta;
import cr.co.tse.padronelectoral.domain.VotanteInfo;

/**
 * Service to search on the index.
 * 
 * @author jsanca
 * 
 */
public class IndexSearchService {

	private static final int DEFAULT_RESULTS_SIZE = 40;
	private IndexSearcher searcher = null;
	private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyddMM");

	public IndexSearchService(File directoy) throws CorruptIndexException,
			IOException {

		this.searcher = new IndexSearcher(new SimpleFSDirectory(directoy), true);
	}

	/**
	 * Busqueda por diferentes campos y consultas.
	 * @param nameField String []
	 * @param queries String []
	 * @return Collection<VotanteInfo>
	 * @throws Exception
	 */
	public Collection<VotanteInfo> search(String[] nameField, String[] queries)
			throws Exception {

		// Build a Query object
		Query query = MultiFieldQueryParser.parse(queries, nameField,
				new StandardAnalyzer());
		// Search for the query
		return this.runQuery(Arrays.asList(queries), query);

	} // search.

	private Collection<VotanteInfo> runQuery(Object queries, Query query)
			throws IOException, NotMatchesWereFoundException,
			CorruptIndexException, java.text.ParseException {

		int hitCount;

		ScoreDoc[] scoreDocs = this.searcher
				.search(query, DEFAULT_RESULTS_SIZE).scoreDocs;
		Document doc = null;
		Collection<VotanteInfo> collectionVotantes = new ArrayList<VotanteInfo>();

		// Examine the Hits object to see if there were any matches
		hitCount = scoreDocs.length;
		if (hitCount == 0) {

			throw new NotMatchesWereFoundException(
					"No matches were found for \"" + queries + "\"");
		} else {

			// Iterate over the Documents in the Hits object
			for (int i = 0; i < hitCount; i++) {
				doc = this.searcher.doc(scoreDocs[i].doc);

				collectionVotantes.add(mappingVotante(doc));
			}
		}

		return collectionVotantes; 
	} // runQuery.

	/**
	 * Searches for the given string in the "content" field
	 * 
	 * @throws IOException
	 * @throws CorruptIndexException
	 * @throws ParseException
	 */
	public Collection<VotanteInfo> search(String nameField, String queryString)
			throws Exception {

		QueryParser queryParser = new QueryParser(nameField,
				new StandardAnalyzer());
		// Build a Query object
		Query query = queryParser.parse(queryString);

		return this.runQuery(queryString, query);
	} // search.

	/**
	 * Close the index.
	 * @throws IOException
	 */
	public void closeSearcher() throws IOException {

		this.searcher.close();
	} // closeSearcher.

	private VotanteInfo mappingVotante(Document doc)
			throws java.text.ParseException {

		VotanteInfo votanteInfo = new VotanteInfo();
		Junta junta = new Junta();
		votanteInfo.setApellido1(doc.getField("apellido1").stringValue());
		votanteInfo.setApellido2(doc.getField("apellido2").stringValue());
		votanteInfo.setCanton(doc.getField("canton").stringValue());
		votanteInfo.setCedula(Integer.parseInt(doc.getField("cedula")
				.stringValue()));
		votanteInfo.setFechavencimiento(dateFormat.parse(doc.getField(
				"fechavencimiento").stringValue()));
		votanteInfo.setJuntareceptora(doc.getField("juntareceptora")
				.stringValue());
		votanteInfo.setLugarElectoralInscrito(doc.getField(
				"lugarelectoralinscrito").stringValue());
		votanteInfo.setNombre(doc.getField("nombre").stringValue());
		votanteInfo.setProvincia(doc.getField("provincia").stringValue());
		votanteInfo.setSexo("1".equalsIgnoreCase(doc.getField("sexo")
				.stringValue()) ? "Hombre" : "Mujer");

		junta.setNumeroJunta(doc.getField("juntareceptora").stringValue());

		if (null != doc.getField("juntadireccion")) {

			junta.setDireccion(doc.getField("juntadireccion").stringValue());
			junta.setNombreJunta(doc.getField("juntanombre").stringValue());
		}

		votanteInfo.setJunta(junta);

		return votanteInfo;
	} // mappingVotante.

} // E:O:F:IndexSearch.
